package com.merry.spring5.reflex.ioc.bean;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.util.StringUtils;

import com.merry.spring5.reflex.ioc.annotation.Bean;
import com.merry.spring5.reflex.ioc.annotation.DI;
import com.merry.spring5.reflex.ioc.test.Water;

/**
 * @author ybzou
 * @see org.springframework.context.annotation.AnnotationConfigApplicationContext
 */
public class AnnotationApplicationCon implements ApplicationCon{

    private Map<String,Object> beanMap=new HashMap<String,Object>();
    private String basePackage;
    private String rootPath;

    public Object getBean(String name) {
        return beanMap.get(name);
    }

    public AnnotationApplicationCon(String basePackage) throws Exception {
        this.basePackage=basePackage;
        refreshBean();
    }

    private void refreshBean() throws Exception {
        //1.把.替换成\
        String packagePath = basePackage.replaceAll("\\.", "\\\\");
        //2.获取包的绝对路径
        Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
        while (urls.hasMoreElements()){
            URL url = urls.nextElement();
            String filePath = URLDecoder.decode(url.getFile(), "utf-8");
            rootPath=filePath.substring(0, filePath.length()-packagePath.length());

            //3.包扫描
            loadBean(new File(filePath));
        }

        //4.完成属性注入
        loadDI();
    }

    private void loadDI() throws IllegalAccessException {
        //1.遍历map集合，获取每个对象中的属性。
        Set<String> set = beanMap.keySet();
        for (String beanName : set) {
            Object bean = beanMap.get(beanName);
            //2.查看属性中是否有@DI注解。
            Class<?> aClass = bean.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                DI annotation = declaredField.getAnnotation(DI.class);
                if(annotation!=null){
                    //3.如果有则可以注入。
                    String requestName = annotation.value();
                    if(!StringUtils.hasText(requestName)){
                        //如果没有value属性，则默认为属性名。
                        requestName=declaredField.getName().toLowerCase();
                    }
                    declaredField.setAccessible(true);
                    //依赖注入
                    //这里没有解决循环依赖问题。运行当前的代码可能会出现循环依赖的情况。
                    //TODO:解决循环依赖
                    declaredField.set(bean,beanMap.get(requestName));
                }
            }
        }
    }

    private void loadBean(File file) throws Exception {
        //1.判断当前是否是文件夹
        if(file.isDirectory()){
            //2.获取文件夹里面的内容
            File[] childFiles = file.listFiles();

            //3.判断文件夹是否为空，为空返回
            if(childFiles == null || childFiles.length==0){
                return;
            }

            //4.如果不为空，遍历里面所有内容
            for (File childFile : childFiles) {
                //4.1 得到每个file对象，继续递归判断。
                if(childFile.isDirectory()){
                    loadBean(childFile);
                }else{
                    //4.2 遍历得到的不是文件夹，是文件。
                    //4.3 得到这个java文件的全类名。
                    String pathWithClass = childFile.getAbsolutePath().substring(rootPath.length()-1);

                    //4.4 判断当前文件类型是否是 .class类型
                    if (pathWithClass.contains(".class")) {
                        //4.5 如果是.class类型，把路径中的\替换成.，并将 .class去掉
                        String className = pathWithClass.replaceAll("\\\\", ".").replaceAll(".class", "");
                        //4.6 判断类上面是否有@bean注解，如果有则实例化。
                        Class<?> aClass = Class.forName(className);
                        //不是接口
                        if (!aClass.isInterface()) {
                            //是否含有注解@bean
                            Bean annotation = aClass.getAnnotation(Bean.class);
                            if(annotation !=null){
                                //获取注解中的value属性，如果没有，默认就是类名小写。
                                String name = annotation.value();
                                if(!StringUtils.hasText(name)){
                                    name=aClass.getSimpleName().toLowerCase();
                                }
                                //含有注解，实例化
                                Object instance = aClass.getConstructor().newInstance();
                                //将instance存放到map中
                                beanMap.put(name,instance);
                            }
                        }
                    }
                }
            }
        }
    }


    public static void main(String[] args) throws Exception {
        ApplicationCon applicationCon=new AnnotationApplicationCon("com.merry.spring5.reflex");
        Water water = (Water) applicationCon.getBean("water");
        water.water();
        water.getWaterTissue().waterTissue();
    }
}
